package msi.gama.display.java3d.scenegraph;

import java.util.Enumeration;

import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Group;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Vector3f;

import msi.gama.display.java3d.coordinate.CoordinateObject;
import msi.gama.display.java3d.renderingObject.RenderingObject;

import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;

/**
 * minhvv, p18, IFI, TPE 01/2014 - 07/2014
 */

public class J3DSceneGraph {
	private BranchGroup mainBranch = null;
	private BranchGroup contentBranch = null;
	private TransformGroup root = null;

	public BranchGroup createSceneGraph() {
		contentBranch = new BranchGroup();

		root = new TransformGroup();
		root.addChild(contentBranch);

		mainBranch = new BranchGroup();
		mainBranch.addChild(root);

		setCapacities();
		addMouseAction();
		addCoordinateObject();
		initViewPort();

		contentBranch.compile();
		mainBranch.compile();

		return mainBranch;
	}

	private void addCoordinateObject() {
		CoordinateObject coordObj = new CoordinateObject();
		root.addChild(coordObj.getScene());
	}

	private void setCapacities() {

		contentBranch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
		contentBranch.setCapability(Group.ALLOW_CHILDREN_WRITE);
		contentBranch.setCapability(Group.ALLOW_CHILDREN_READ);

		root.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		root.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		root.setCapability(Group.ALLOW_CHILDREN_EXTEND);
		root.setCapability(Group.ALLOW_CHILDREN_READ);
		root.setCapability(Group.ALLOW_CHILDREN_WRITE);
	}

	private void addMouseAction() {
		MouseRotate mouseRotate = new MouseRotate();
		mouseRotate.setTransformGroup(root);
		mouseRotate.setSchedulingBounds(new BoundingSphere());
		root.addChild(mouseRotate);

		MouseTranslate myMouseTranslate = new MouseTranslate();
		myMouseTranslate.setTransformGroup(root);
		myMouseTranslate.setSchedulingBounds(new BoundingSphere());
		root.addChild(myMouseTranslate);

		MouseZoom myMouseZoom = new MouseZoom();
		myMouseZoom.setTransformGroup(root);
		myMouseZoom.setSchedulingBounds(new BoundingSphere());
		root.addChild(myMouseZoom);
	}

	public void addRenderingObject(RenderingObject renderingObj) {
		contentBranch.addChild(renderingObj.getScene());
	}

	public void updateSceneAfterEachFrame() {
		autoRemoveDeadObjects();
	}

	private void autoRemoveDeadObjects() {
		Enumeration<?> allBranchChild = contentBranch.getAllChildren();
		while (allBranchChild.hasMoreElements()) {
			Object object = allBranchChild.nextElement();
			if (object instanceof BranchGroup) {
				BranchGroup currentBranch = (BranchGroup) object;
				RenderingObject renderingObj = (RenderingObject)
						currentBranch.getUserData();

				if (renderingObj.isObjectDead()) {
					contentBranch.removeChild(currentBranch);
				}
			}
		}
	}

	private void initViewPort() {
		Vector3f vtran = new Vector3f(-0.5f, -0.5f, -0.50f);
		Transform3D transform = new Transform3D();
		transform.setTranslation(vtran);
		root.setTransform(transform);
	}

	public void resetRotate() {
		// Transform3D noRotate = new Transform3D();
		// noRotate.rotX(0);
		// noRotate.rotY(0);
		// root.setTransform(noRotate);
		initViewPort();
	}

	private Vector3f currentScreenPos = new Vector3f(-0.5f, -0.5f, -0.50f);

	public void moveScreen(float offsetX, float offsetY) {
		currentScreenPos.add(new Vector3f(offsetX, offsetY, 0.0f));
		Transform3D transform = new Transform3D();
		transform.setTranslation(currentScreenPos);
		root.setTransform(transform);

	}

	public void dump() {
		System.out.println("\nSceneGrapha:");
		Enumeration<?> allChildren = contentBranch.getAllChildren();
		while (allChildren.hasMoreElements()) {
			Object oneBranch = allChildren.nextElement();
			if (oneBranch instanceof BranchGroup) {
				RenderingObject obj = (RenderingObject) ((BranchGroup) oneBranch).getUserData();
				System.out.println("RENDERINGOBJECT: " + obj.toString());
			}
		}
	}

	// TODO minhvv REMOVE AFTER TESTING

	// public void deleteObj(String objId) {
	// int index = searchById(objId);
	// if (index < contentBranch.numChildren()) {
	// contentBranch.removeChild(index);
	// }
	// }
	//
	// private int searchById(String objId) {
	// int index = 0;
	//
	// Enumeration<?> allBranchChild = contentBranch.getAllChildren();
	// while (allBranchChild.hasMoreElements()) {
	// Object object = allBranchChild.nextElement();
	// if (object instanceof BranchGroup) {
	// BranchGroup bg = (BranchGroup) object;
	// RenderingObject renderingObj = (RenderingObject) bg.getUserData();
	//
	// if (!renderingObj.isMatch(objId)) {
	// index++;
	// } else {
	// break;
	// }
	// }
	// }
	//
	// return index;
	// }

	// public void moveObj(String objId, Vector3f newPosition) {
	// Enumeration<?> allBranchChild = contentBranch.getAllChildren();
	// while (allBranchChild.hasMoreElements()) {
	// Object object = allBranchChild.nextElement();
	// if (object instanceof BranchGroup) {
	// BranchGroup bg = (BranchGroup) object;
	// RenderingObject renderingObj = (RenderingObject) bg.getUserData();
	//
	// if (renderingObj.isMatch(objId)) {
	// // renderingObj.moveTo(newPosition);
	// }
	// }
	// }
	// }
	//
	// private void testScene() {
	// Transform3D transform = new Transform3D();
	// transform.rotX(Math.PI / 4);
	// Vector3d vTranslate = new Vector3d(0.2, 0.2, 0.2);
	// transform.transform(vTranslate);
	// root.setTransform(transform);
	//
	// contentBranch.addChild(new ColorCube(0.2));
	// }
}
